package com.nolon.flange.model

import androidx.room.*
import com.nolon.flange.model.RawInfo
import com.nolon.flange.model.Part

@Entity(tableName = "raw_solution_table")
data class RawSolution(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    @ColumnInfo(name = "project_id") val projectId: Int,
    @Embedded val rawInfo: RawInfo,
    @ColumnInfo(name = "usage_rate") val usageRate: Float = 0f,
    @ColumnInfo(name = "tail_length") val tailLength: Int = 0,
    var count: Int
) {
    @Ignore
    var parts: ArrayList<Part> = arrayListOf()

    @Ignore
    val partsPlain: ArrayList<Int> = arrayListOf()

    @Ignore
    var combination: Int = 0

    @Ignore
    fun usageRate(): Float = usedLength().toFloat() / rawInfo.length

    @Ignore
    fun tailLength() = rawInfo.length - usedLength()

    @Ignore
    fun usedLength(): Int =
        if (parts.isEmpty()) 0 else parts.map { it.quantity }.reduce { acc, f -> acc + f }

    @Ignore
    fun ifRoom(part: Part): Boolean {
        val existed = parts.find { it.quantity == part.quantity }
        return if (usedLength() + part.quantity <= rawInfo.length && combination <= rawInfo.maxCombination) {
            parts.add(part)
            parts.sortBy { it.quantity }
            if (existed == null) {
                combination++
            }
            true
        } else false
    }

    @Ignore
    fun info(): String {
        val types = parts.map { it.quantity }.toSet().toList()
        var str = ""
        types.forEach { f ->
            str += f.toString() + " × " + parts.count { it.quantity == f } + "\n"
        }
        return str.trimEnd('\n')
    }

    fun mayI(part: Part): Boolean {
        if (partsPlain.isNotEmpty()) {
            var index = -1
            with(index) loop@{
                partsPlain.forEachIndexed { i, f ->
                    if (f == part.quantity) {
                        index = i
                        return@loop
                    }
                }
            }
            if (index != -1) {
                parts.add(part)
                partsPlain.removeAt(index)
                return true
            }
            return false
        } else {
            return false
        }
    }
}
